﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using ContosoUniversity.Data;
using ContosoUniversity.Models;
using ContosoUniversity.Tools;

namespace ContosoUniversity.Controllers
{
    public class StudentsController : Controller
    {
        private readonly SchoolContext _context;

        public StudentsController(SchoolContext context)
        {
            _context = context;
        }

        /// <summary>
        /// 异步编程是asp.net core和ef core默认的行为
        /// 高负载的情况下，web服务器的所有主线程都可能在使用
        /// 发生这样的情况，服务器就不能处理其他的请求，直到线程被释放
        /// 使用同步代码，许多线程都被绑定，单实际情况是他们并没有在工作，只是在等待i/o操作完成
        /// 使用异步编程的话，在等待i/o操作的是时候，他的线程会被释放，提供服务器处理其他的请求
        /// 这样就能处理更多的流量
        /// </summary>
        /// <returns></returns>

        // GET: Students
        public async Task<IActionResult> Index(string sortOrder, string currentFilter, int? page)
        {
            ViewData["NameSortParm"] = string.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
            ViewData["DateSortParm"] = sortOrder == "date" ? "date_desc" : "date";
            ViewData["currentFilter"] = currentFilter;

            var students = from s in _context.Students
                           select s;

            if (!string.IsNullOrEmpty(currentFilter))
            {
                students = students.Where(t => t.LastName.Contains(currentFilter) || t.FirstMidName.Contains(currentFilter));
            }

            switch (sortOrder)
            {
                case "name_desc":
                    students = students.OrderByDescending(t => t.LastName);
                    break;
                case "date":
                    students = students.OrderBy(t => t.EnrollmentDate);
                    break;
                case "date_desc":
                    students = students.OrderByDescending(t => t.EnrollmentDate);
                    break;
                default:
                    students = students.OrderBy(t => t.LastName);
                    break;
            }

            return View(await PaginatedList<Student>.CreateAsync(students.AsNoTracking(), page ?? 1, 3));
        }

        // GET: Students/Details/5
        public async Task<IActionResult> Details(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var student = await _context.Students
                .SingleOrDefaultAsync(m => m.ID == id);
            if (student == null)
            {
                return NotFound();
            }

            return View(student);
        }

        // GET: Students/Create
        public IActionResult Create()
        {
            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Create([Bind("LastName,FirstMidName,EnrollmentDate")]Student student)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    _context.Add(student);
                    await _context.SaveChangesAsync();
                    return RedirectToAction(nameof(Index));
                }
            }
            catch (Exception)
            {
                ModelState.AddModelError("", "Unable to save changes");
            }
            return View(student);
        }

        // GET: Students/Edit/5
        public async Task<IActionResult> Edit(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var student = await _context.Students.SingleOrDefaultAsync(m => m.ID == id);
            if (student == null)
            {
                return NotFound();
            }
            return View(student);
        }


        /// <summary>
        /// 部分更新
        /// 但是得重新查询数据库
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpPost, ActionName("Edit")]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> EditPost(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var studentToUpdate = await _context.Students.SingleOrDefaultAsync(t => t.ID == id);
            if (await TryUpdateModelAsync<Student>(studentToUpdate, "", s => s.LastName, s => s.EnrollmentDate))
            {
                try
                {
                    await _context.SaveChangesAsync();
                    return RedirectToAction(nameof(Index));
                }
                catch (Exception)
                {
                    ModelState.AddModelError("", "Unable to save changes.");
                }
            }
            return View(studentToUpdate);
        }
        /// <summary>
        /// 全部更新
        /// </summary>
        /// <param name="id"></param>
        /// <param name="student"></param>
        /// <returns></returns>
        //[HttpPost]
        //[ValidateAntiForgeryToken]
        //public async Task<IActionResult> Edit(int id, [Bind("ID,LastName,FirstMidName,EnrollmentDate")] Student student)
        //{
        //    if (id != student.ID)
        //    {
        //        return NotFound();
        //    }

        //    if (ModelState.IsValid)
        //    {
        //        try
        //        {
        //            _context.Update(student);
        //            await _context.SaveChangesAsync();
        //        }
        //        catch (DbUpdateConcurrencyException)
        //        {
        //            if (!StudentExists(student.ID))
        //            {
        //                return NotFound();
        //            }
        //            else
        //            {
        //                throw;
        //            }
        //        }
        //        return RedirectToAction(nameof(Index));
        //    }
        //    return View(student);
        //}

        // GET: Students/Delete/5
        public async Task<IActionResult> Delete(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var student = await _context.Students
                                        .AsNoTracking().SingleOrDefaultAsync(m => m.ID == id);
            if (student == null)
            {
                return NotFound();
            }

            return View(student);
        }

        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> DeleteConfirmed(int id)
        {
            var student = await _context.Students.AsNoTracking().SingleOrDefaultAsync(m => m.ID == id);
            if (student == null)
            {
                return RedirectToAction(nameof(Index));
            }
            try
            {
                _context.Students.Remove(student);
                await _context.SaveChangesAsync();
                return RedirectToAction(nameof(Index));
            }
            catch (Exception)
            {
                return RedirectToAction(nameof(DeleteErr), new { id = id, saveChangeError = true });
            }
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> DeleteErr(int? id, bool? saveChangeError = false)
        {
            if (id == null)
            {
                return NotFound();
            }
            var student = await _context.Students.AsNoTracking().SingleOrDefaultAsync(t => t.ID == id);
            if (student == null)
            {
                return NotFound();
            }
            if (saveChangeError.GetValueOrDefault())
            {
                ViewData["ErrorMsg"] = "Delete failed. Try again";
            }
            return View(student);
        }

        private bool StudentExists(int id)
        {
            return _context.Students.Any(e => e.ID == id);
        }


    }
}
